package spring.config;

import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;
import spring.annotation.ZhangScan;
import spring.factorybean.MyFactoryBean;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhangyan
 * @version $ Id: ImportBeanDefinitionRegistrarImpl.java, v 0.1 2020/5/14 13:32 zhangyan Exp $
 */
public class ImportBeanDefinitionRegistrarImpl implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//获取自定义扫描注解
		Map<String, Object> scanMap = importingClassMetadata.getAnnotationAttributes(ZhangScan.class.getName());
		String basePackage = (String) scanMap.get("basePackage");
		basePackage = StringUtils.replace(basePackage, ".", "/");
		List<Map<String, String>> aPackage = getPackage(basePackage);
		for (Map<String, String> map : aPackage) {
			BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(map.get("class"));
			GenericBeanDefinition beanDefinition = (GenericBeanDefinition) builder.getBeanDefinition();
			//因为factoryBean.getObject方法返回的是代理对象，所以我们需要将TestMapper.class传进去
			ConstructorArgumentValues argumentValues = beanDefinition.getConstructorArgumentValues();
			argumentValues.addGenericArgumentValue(map.get("class"));
			//动态修改beanClass为FactoryBean
			beanDefinition.setBeanClass(MyFactoryBean.class);
			//将beanDefinition注册到spring容器中
			registry.registerBeanDefinition(map.get("beanName"), beanDefinition);
		}


	}

	private List<Map<String, String>> getPackage(String basePackage) {
		//扫描包下所有接口
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		URL url = loader.getResource(basePackage);
		File targetFile = new File(url.getFile());
		if (!targetFile.exists() || targetFile.isFile()) {
			throw new RuntimeException(basePackage + "不是一个包名或者该包名不存在");
		}
		return getAllClass(targetFile, basePackage);
	}

	/**
	 * 得到所有在parentFile目录下的class文件名称
	 *
	 * @param parentFile
	 * @param basePackageName
	 */
	private static List<Map<String, String>> getAllClass(File parentFile, String basePackageName) {
		List<Map<String, String>> mapList = new ArrayList<>();
		File[] files = parentFile.listFiles();
		for (File file : files) {
			String path = file.getPath();
			if (file.isFile()) {
				HashMap<String, String> map = new HashMap<>();
				if (path.endsWith(".class")) {
					int i = path.lastIndexOf("\\");
					String substring = path.substring(i + 1, path.length() - 6);
					map.put("beanName", substring);
					map.put("class", StringUtils.replace(basePackageName, "/", ".") + "." + substring);
					mapList.add(map);
				}
			} else {
				basePackageName = basePackageName + path.substring(path.lastIndexOf('\\') + 1);
				getAllClass(file, basePackageName);
			}
		}
		return mapList;
	}
}
